/**
 * 
 */
package common.project.epic.core;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;

import common.project.epic.db.EpicDBAdapter;

/**
 * @author Luca
 *
 */
public class LocationEpicService extends Service {

	// Reference to the system Location Manager
	private LocationManager locationManager; 
	private static Location currentBetterLocation;
	private static  int LOCATION_TIME_WINDOW = 60000 * 5;
	private static Criteria criteria;
	private static String provider;
	private static EpicDBAdapter myDBAdapter;
	int mStartMode = START_STICKY;
	
	
		
	    @Override
	    public void onCreate() {
//	    	android.os.Debug.waitForDebugger();
	    	myDBAdapter = new EpicDBAdapter(getApplicationContext());
	    	criteria = new Criteria();
    		criteria.setAccuracy(Criteria.ACCURACY_COARSE);
    		criteria.setPowerRequirement(Criteria.POWER_LOW);
    		criteria.setAltitudeRequired(false);
    		criteria.setBearingRequired(false);
    		criteria.setSpeedRequired(false);
    		criteria.setCostAllowed(true);	
    		String context = Context.LOCATION_SERVICE;
    		locationManager = (LocationManager)getSystemService(context);
    		provider =  locationManager.getBestProvider(criteria, false);
		   
	    }

	    @Override
	    public int onStartCommand(Intent intent, int flags, int startId) {
	    	locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
		    // Register the listener with the Location Manager to receive location updates
		    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 0, locationListener);
		    // Register the listener with the Location Manager to receive location updates
		    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 120*1000, 0, locationListener);
	    	return mStartMode;
	    	
	    }

	    @Override
	    	public void onDestroy() {
    			locationManager.removeUpdates(locationListener);
	    	}

	    // Define a listener that responds to location updates
		LocationListener locationListener = new LocationListener() {
		    public void onLocationChanged(Location location) {
		      // Called when a new location is found
		    	if(isBetterLocation(location , currentBetterLocation)){
		    		setBetterLocation(location);
		    		
		    		myDBAdapter.open();
		    		Cursor cursor = myDBAdapter.getDeferredContents();
		    		if(cursor.getCount() != 0){
		    			
		    			cursor.moveToFirst();
		    			while(cursor.isLast()){
		    				String msgid = cursor.getString(cursor.getColumnIndex("Epic_message_id"));
		    				myDBAdapter.markAsSent(msgid, location);
		    				cursor.moveToNext();
		    			}
		    			
		    		}
		    		myDBAdapter.close();
		    	}
		    }
		
		    public void onStatusChanged(String provider, int status, Bundle extras) {
		    	//do nothing
		    	
		    }
		
		    public void onProviderEnabled(String provider) {
		    	if(provider == LocationManager.GPS_PROVIDER){
		    		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
		    	}
		    	if(provider == LocationManager.NETWORK_PROVIDER){
		    		locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
		    	}
		    }
		
		    public void onProviderDisabled(String provider) {
		    	//do nothing
		    	
		    }
		  };
	

		  protected boolean isBetterLocation(Location location, Location currentBestLocation) {
			    
			  if (currentBestLocation == null && location != null) {
			        // A new location is always better than no location
			        return true;
			    }

			    // Check whether the new location fix is newer or older
			    long timeDelta = location.getTime() - currentBestLocation.getTime();
			    boolean isSignificantlyNewer = timeDelta > LOCATION_TIME_WINDOW;
			    boolean isSignificantlyOlder = timeDelta < -LOCATION_TIME_WINDOW;
			    boolean isNewer = timeDelta > 0;
			    
			    // If it's been more than two minutes since the current location, use the new location
			    // because the user has likely moved
			    if (isSignificantlyNewer) {
			        return true;
			    // If the new location is more than two minutes older, it must be worse
			    } else if (isSignificantlyOlder) {
			        return false;
			    }

			    // Check whether the new location fix is more or less accurate
			    int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
			    boolean isLessAccurate = accuracyDelta > 0;
			    boolean isMoreAccurate = accuracyDelta < 0;

			    // Check if the old and new location are from the same provider
			    boolean isFromSameProvider = isSameProvider(location.getProvider(),
			            currentBestLocation.getProvider());

			    // Determine location quality using a combination of timeliness and accuracy
			    if (isMoreAccurate) {
			        return true;
			    } else if (isNewer && !isLessAccurate) {
			        return true;
			    } else if (isNewer && !isLessAccurate && isFromSameProvider) {
			        return true;
			    }
			    return false;
			}
	
		  protected void setBetterLocation(Location location) {
			  
			  LocationEpicService.currentBetterLocation = location;
			  
		  }
		  
		  
		  
		  private boolean isSameProvider(String provider1, String provider2) {
		      if (provider1 == null) {
		        return provider2 == null;
		      }
		      return provider1.equals(provider2);
		  }
		  
			private void setTimeWindow(int time) {
				LocationEpicService.LOCATION_TIME_WINDOW = time;
				
			};

		@Override
		public IBinder onBind(Intent arg0) {
			// TODO Auto-generated method stub
			return mSecondaryBinder;
			
		}		
		 /**
	     * The IObindService interface to the service implementation
	     */
		private final ILocationEpicService.Stub mSecondaryBinder = new ILocationEpicService.Stub() {
	
				@Override
				public Location refreshLocation() throws RemoteException {
						
						provider =  locationManager.getBestProvider(criteria, false);
						if(provider != null){
//						Location temp = locationManager.getLastKnownLocation(provider);
//						
//						if(isBetterLocation(currentBetterLocation, temp)){
//								return currentBetterLocation;
//							}
//							else if (isBetterLocation(temp , currentBetterLocation)){
//								return temp;
//							}
						
						}
					
					return currentBetterLocation;
					
				}

				@Override
				public Location getLastKnownLocation() throws RemoteException {
					if(provider==null){
						return null;
					}else{
						return locationManager.getLastKnownLocation(provider);
					}
				}
		
			};
			

	
	}
